<?php

require_once 'classes/PostGenericAction.php';

class PostComment extends PostGenericAction {
    
    var $constructor_args = array(
        'mail_post_author_only'=>'notify only the post author on new comments, uncheck to notify also administrators and editors',
        'logfile'=>'log comment activity to file, useful for debugging comment spam together with the PostCommentDebug plugin');
    var $default_context = 24; // LP_CONTEXT_POST | LP_CONTEXT_STATIC
    var $description = 'Manage posts comments';
    
    
    var $active = true;
    var $hooks = array('parse_post');
    
    var $logfile = '';
    var $_logfile;
    var $_uniqid;
    
    var $mail_post_author_only = false;
    
    var $_post;
    var $_comment_id;
    var $_wp_htmltranswinuni = array(
        '&#128;' => '&#8364;', // the Euro sign
        '&#129;' => '',
        '&#130;' => '&#8218;', // these are Windows CP1252 specific characters
        '&#131;' => '&#402;',  // they would look weird on non-Windows browsers
        '&#132;' => '&#8222;',
        '&#133;' => '&#8230;',
        '&#134;' => '&#8224;',
        '&#135;' => '&#8225;',
        '&#136;' => '&#710;',
        '&#137;' => '&#8240;',
        '&#138;' => '&#352;',
        '&#139;' => '&#8249;',
        '&#140;' => '&#338;',
        '&#141;' => '',
        '&#142;' => '&#382;',
        '&#143;' => '',
        '&#144;' => '',
        '&#145;' => '&#8216;',
        '&#146;' => '&#8217;',
        '&#147;' => '&#8220;',
        '&#148;' => '&#8221;',
        '&#149;' => '&#8226;',
        '&#150;' => '&#8211;',
        '&#151;' => '&#8212;',
        '&#152;' => '&#732;',
        '&#153;' => '&#8482;',
        '&#154;' => '&#353;',
        '&#155;' => '&#8250;',
        '&#156;' => '&#339;',
        '&#157;' => '',
        '&#158;' => '',
        '&#159;' => '&#376;');

    
    function PostComment(&$frontend, $args, $dummy_run=false) {
        $this->PostGenericAction($frontend, $args, $dummy_run);
    }
    
    function run($hook, &$post) {
        
        if (!empty($this->logfile)) {
            $f = @fopen($this->logfile, 'a');
            if (is_resource($f)) {
                $this->_logfile =& $f;
                $this->_uniqid = strftime("%Y%m%d%H%M%S") . '_' . uniqid();
            }
        }
        
        $this->_post =& $post;
        $this->_comment_id = null;
        
        $tpl =& $this->_frontend->tpl;
        $messages =& $this->_frontend->messages;
        $options =& $this->_frontend->options;
        
        $action =& $this->_action;
        
        // a trackback?
        $trackback = ($action == 'trackback') ? true : false;
        
        $now = time();
        
        if ($trackback) {
            
            $this->debug("trackback received", __LINE__);
            
            if ($post['ping_status'] != 'open')
                $this->trackback_error("Trackbacks closed for this post");
            
            $tb_fields = array('title', 'excerpt', 'url', 'blog_name', 'charset');
            $this->_bootstrap($post, '', true, false, $tb_fields);
            
            // check trackback 
            $user_data =& $this->_user_data;
            
            if (empty($user_data['ud_url']))
                $this->trackback_error("No URL in request vars");
            
            if (!preg_match('/^[a-zA-Z]+:\/\//', $user_data['ud_url']))
                $this->trackback_error("Incorrect URL format.");
            
            // fix encoding in received field values
            $tb_charset = strtoupper(trim($user_data['ud_charset']));
            if (!empty($tb_charset) && function_exists('mb_convert_encoding') && $tb_charset != $options['charset']) {
                foreach ($tb_fields as $tb_var)
                    $user_data[$tb_var] = mb_convert_encoding($user_data[$tb_var], $options['charset'], $tb_charset);
            }
            
            $comment = array(
                'post_id'=>$this->_post['post_id'], 'date'=>$now,
                'author'=>'Anonymous Trackback', 'email'=>'',
                'url'=>$user_data['ud_url'], 'comment'=>$user_data['ud_excerpt'],
                'type'=>'trackback', 'approved'=>'0');
            
            if (!empty($user_data['ud_blog_name']))
                $comment['author'] = $user_data['ud_blog_name'];
            
            if (!empty($user_data['ud_title'])) {
                $comment['comment'] = "<a href=\"{$user_data['ud_url']}\">{$user_data['ud_title']}</a>{$comment['comment']}";
            }
            
            $comment['comment'] = $this->wp_formatting($comment['comment']);
            
            $this->debug("inserting trackback", __LINE__);
            
            // TODO: build the comment array structure here, and pass it as a reference to insertComment
            // TODO: check query result
            $this->_frontend->insertComment($comment, true);
            
            $this->debug("sending notification", __LINE__);
            
            $this->sendNotification($comment);
            
            $this->trackback_success();
            
        } else {

            $this->debug("comment received", __LINE__);
            
            $comment_add_block = $tpl->setBlock('index', 'comment_add', 'BLOCK_COMMENT_ADD', false);
            
            if ($post['skip_form']) {
                // we can't display the form as something else is happening
                // (eg the "send post to a friend" form)
                $tpl->setVar('PLUGIN_POSTCOMMENT', ' ');
                if ($comment_add_block)
                    $tpl->setVar('BLOCK_COMMENT_ADD', $messages['comments_closed']);
                return;
            }
        
            if ($post['comment_status'] != 'open') {
                $this->debug("comment status closed", __LINE__, true);
                // comments are closed, let's hide the plugin's template tag
                $tpl->setVar('PLUGIN_POSTCOMMENT', ' ');
                // and change the link above the comennts list
                if ($comment_add_block)
                    $tpl->setVar('BLOCK_COMMENT_ADD', $messages['comments_closed']);
                return;
            }
            
            if ($comment_add_block)
                $tpl->parse('BLOCK_COMMENT_ADD', 'comment_add');
            
            $this->_bootstrap($post, $messages['comment_form_message']);
            
            // too lazy to add $this->_ to every variable
            $message =& $this->_message;
            $message_class =& $this->_message_class;
            $user_data =& $this->_user_data;
            $labels =& $this->_labels;

            // handle comment submission
            if ($action == 'post_comment') {
            
                $this->debug("handling comment submission", __LINE__);

                // check comment fields
                $empty_fields = array();
                foreach (array('name', 'email', 'text') as $key) {
                    if (empty($user_data["ud_$key"]))
                        $empty_fields[] = $key;
                }
                if (count($empty_fields) == 0) {
                
                    $comment = array(
                        'post_id'=>$this->_post['post_id'], 'date'=>$now,
                        'author'=>$user_data['ud_name'], 'email'=>$user_data['ud_email'],
                        'url'=>$user_data['ud_url'],
                        'comment'=>$this->wp_formatting($user_data['ud_text']),
                        'type'=>'', 'approved'=>'0');
                    
                    $this->_frontend->insertComment($comment);
                    
                    $this->sendNotification($comment);
                    
                    // check if we have to remove the user cookie
                    if (!isset($_REQUEST['remember']) || $_REQUEST['remember'] != '1')
                        $this->_frontend->removeUserCookie();
                    
                    // redirect user so that he does not insert the comment twice
                    $this->_frontend->redirectToPost($post['post_permalink'], $messages['comment_accepted']);
                    
                } else {
                    $this->debug("comment errors, redisplaying comment form", __LINE__, true);
                    // we have errors, let's set warnings
                    foreach ($empty_fields as $empty_field)
                        $user_data["ud_label_$empty_field"] = "warning";
                    $message = $messages['comment_required_fields']; // . implode(", ", $empty_fields);
                    $message_class = 'comment_form_warning';
                }
            }
            // no action, let's set user data and display the form
            
            $this->debug("no action, redisplaying comment form", __LINE__, true);
            
            $tpl->setVar($user_data);
            $tpl->setVar(array(
                'comment_form_message'          => $message,
                'comment_form_message_class'    => $message_class));
            $tpl->setFile('plugin_postcomment', 'plugins/post_comment.xml');
            $tpl->parse('PLUGIN_POSTCOMMENT', 'plugin_postcomment');
            
        }
    }
    
    function sendNotification(&$comment) {
        
        // TODO: check for approval status and mail sending options
        // TODO: use different templates based on approval status

        $this->debug("checking if we have to send a notification", __LINE__);

        $options =& $this->_frontend->options;
        
        // no comment inserted
        if (is_null($comment['id']))
            return;
        // approval status
        switch ($comment['approved']) {
            case '1':
                // approved
                if (!$options['mail_on_comment'])
                    return;
                break;
            case '0':
            case 'spam':
                if (!$options['comment_spam_mail'])
                    return;
        }
        
        $this->debug("sending notification", __LINE__);

        $messages =& $this->_frontend->messages;
        $tpl =& $this->_frontend->tpl;
        $db =& $this->_frontend->db;
        
        $recipients = array();

        $q = "select u.user_email from {$this->_frontend->tables['posts']} p inner join {$this->_frontend->tables['users']} u on p.post_author = u.id where p.id = {$this->_post['post_id']}";
        if ($db->query($q))
            $recipients[$db->get('user_email')] = '';
        
        if (count($recipients) == 0 || !$this->mail_post_author_only) {
            
            $users =& $this->_frontend->getUserPerms();
        
            foreach ($users as $user_id=>$user_data) {
                if ($user_data['user_level'] >= 3)
                    $recipients[$user_data['user_email']] = '';
                else if (isset($user_data['capabilities']['administrator']) || isset($user_data['capabilities']['editor']))
                    $recipients[$user_data['user_email']] = '';
            }
            
        }
        
        $to = implode(', ', array_keys($recipients));
        
        $this->debug("sending notification, recipients $to", __LINE__);
        
        $mh =& $this->_frontend->getMailHelper();

        $this->debug("sending notification, got mail helper", __LINE__);

        $shortname = $mh->htent2qp($options['shortname']);
        $shortname_hdr = $mh->encoded2hdr($options['shortname']);
        $tpl->setVar(array(
            'notify_shortname'          => $shortname,
            'notify_useremails'         => $to,
            'notify_post_title'         => $mh->htent2qp($this->_post['post_title']),
            'notify_post_name'          => $mh->htent2qp($this->_post['post_name']),
            'notify_post_permalink'     => $mh->htent2qp($this->_post['post_permalink']),
            'notify_comment_date'       => $mh->htent2qp(strftime($options['date_format'], $comment['date'])),
            'notify_comment_time'       => $mh->htent2qp(strftime($options['time_format'], $comment['date'])),
            'notify_comment_user'       => $mh->htent2qp($comment['author']),
            'notify_comment_email'      => $mh->htent2qp($comment['email']),
            'notify_comment_ip'         => $_SERVER['REMOTE_ADDR'],
            'notify_comment_agent'      => $_SERVER['HTTP_USER_AGENT'],
            'notify_comment_url'        => $mh->htent2qp($comment['url']),
            'notify_comment_id'         => $comment['id'],
            'notify_comment_type'       => $comment['type'],
            'notify_comment_approved'   => $comment['approved'],
            'notify_comment_text'       => strip_tags($comment['comment'])
            )); 
        $headers = array(
            'Content-Type: text/plain; charset="' . $options['charset'] . '"',
            'MIME-Version: 1.0',
            'Content-Transfer-Encoding: quoted-printable',
            'From: "'. $shortname_hdr . '" <' . $options['mail_from'] . '>');

        $this->debug("sending notification, mail ready to send", __LINE__);
        
        if ($comment['approved'] == '1')
            $tpl->setFile('notify_email', 'plugins/post_comment_notification.txt');
        else
            $tpl->setFile('notify_email', 'plugins/post_comment_notification_spam.txt');
        $content = $tpl->parse('NOTIFY_EMAIL', 'notify_email', false, false);
        
        if (!$content) {
            $tpl->setFile('notify_email', 'plugins/post_comment_notification.txt');
            $content = $tpl->parse('NOTIFY_EMAIL', 'notify_email');
        }
        
        $title = "[$shortname_hdr] " . $mh->encoded2hdr($messages['comment_mail_subject']) . ($comment['approved'] != '1' ? ' (spam)' : '');
        
        $ret = $mh->send_mail($to, $title, $content, implode("\r\n", $headers));

        $this->debug("sending notification, mail sent return $ret", __LINE__, true);
        
        return $ret;
        
    }
    
    function trackback_success() {
        $this->debug("trackback success", __LINE__, true);
        header('Content-Type: text/xml');
        echo '<?xml version="1.0" encoding="' . $this->_frontend->options['charset'] . '"?>' .
            "\n<response><error>0</error></response>\n";
        exit;
    }

    function trackback_error($error="Error inserting trackback") {
        $this->debug("trackback error $error", __LINE__, true);
        header('Content-Type: text/xml');
        echo '<?xml version="1.0" encoding="' . $this->_frontend->options['charset'] . '"?>' .
            "\n<response><error>1</error>" .
            "<message>" . htmlspecialchars($error, ENT_QUOTES) . "</message>" .
            "</response>\n";
        exit;
    }

    function wp_formatting(&$text) {
        // stripped down version of WP's wp_formatting
        // will have to code this properly sooner or later...
        
        $output = '';
        // Capture tags and everything inside them
        $textarr = preg_split("/(<[^>]+>)/s", $text, -1, PREG_SPLIT_DELIM_CAPTURE);

        $next = true;

        foreach ($textarr as $curl) {

            if (empty($curl))
                continue;

            if ($curl[0] == '<') {
                if (strstr($curl, '<code') || strstr($curl, '<pre') || strstr($curl, '<kbd') || strstr($curl, '<style') || strstr($curl, '<script'))
                    $next = false;
                else if (strstr($curl, '</code') || strstr($curl, '</pre') || strstr($curl, '</kbd') || strstr($curl, '</style') || strstr($curl, '</script'))
                    $next = true;
                $output .= $curl;
                continue;
            }

            if (!$next) {
                $output .= $curl;
                continue;
            }

            $curl = str_replace('---', '&#8212;', $curl);
            $curl = str_replace(' -- ', ' &#8212; ', $curl);
            $curl = str_replace('--', '&#8211;', $curl);
            $curl = str_replace('...', '&#8230;', $curl);
            $curl = str_replace('``', '&#8220;', $curl);
            $curl = str_replace("''", '&#8221;', $curl);

            $output .= $curl;
        }

        // Converts lone & characters into &#38; (a.k.a. &amp;)
        $output = preg_replace('/&([^#])(?![a-z]{1,8};)/i', '&#038;$1', $output);
    
        $output = strtr($output, $this->_wp_htmltranswinuni);
        
        // Just a little XHTML help
        $output = str_replace('<br>', '<br />', $output);
        $output = str_replace('<hr>', '<hr />', $output);
        
        return $output;
    }
    
    function debug($message, $line, $close=false) {
        if (is_null($this->_logfile))
            return;
        @fwrite($this->_logfile, "{$this->_uniqid} $line $message\r\n");
        if ($close) {
            @fwrite($this->_logfile, "\r\n");
            @fclose($this->_logfile);
        }
    }
    
}

?>
